10. NumPy 中的转置

转置

在 NumPy 中获得矩阵的转置非常容易。只需访问其 T 属性即可。还有一个 transpose() 函数也可以返回同样的结果,但是你很少看到它的使用,因为输入 T 的方法要简单得多。:)

例如:

m = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
m
# 显示以下结果:
# array([[ 1,  2,  3,  4],
#        [ 5,  6,  7,  8],
#        [ 9, 10, 11, 12]])

m.T
# 显示以下结果:
# array([[ 1,  5,  9],
#        [ 2,  6, 10],
#        [ 3,  7, 11],
#        [ 4,  8, 12]])

NumPy 在进行转置时不会实际移动内存中的任何数据 - 只是改变对原始矩阵的索引方式 - 所以是非常高效的。

但是,这也意味着你要特别注意修改对象的方式,因为它们共享相同的数据。例如,对于上面同一个矩阵 m,我们来创建一个新的变量 m_t 来存储 m 的转置。然后看看如果我们修改 m_t 中的值,会发生什么:

m_t = m.T
m_t[3][1] = 200
m_t
# 显示以下结果:
# array([[ 1,   5, 9],
#        [ 2,   6, 10],
#        [ 3,   7, 11],
#        [ 4, 200, 12]])

m
# 显示以下结果:
# array([[ 1,  2,  3,   4],
#        [ 5,  6,  7, 200],
#        [ 9, 10, 11,  12]])

注意它是如何同时修改转置和原始矩阵的!这是因为它们共享相同的数据副本。所以记住,将转置视为矩阵的不同视图,而不是完全不同的矩阵。

实际用例

我不想过多讲解关于神经网络的细节,因为你还没有学到它们,但是有一个地方你差不多肯定会用到转置,或者至少考虑使用转置。

假设你有以下两个矩阵,称为 inputsweights

inputs = np.array([[-0.27,  0.45,  0.64, 0.31]])
inputs
# 显示以下结果:
# array([[-0.27,  0.45,  0.64,  0.31]])

inputs.shape
# 显示以下结果:
# (1, 4)

weights = np.array([[0.02, 0.001, -0.03, 0.036], \
    [0.04, -0.003, 0.025, 0.009], [0.012, -0.045, 0.28, -0.067]])

weights
# 显示以下结果:
# array([[ 0.02 ,  0.001, -0.03 ,  0.036],
#        [ 0.04 , -0.003,  0.025,  0.009],
#        [ 0.012, -0.045,  0.28 , -0.067]])

weights.shape
# displays the following result:
# (3, 4)

我在这里不会讲解它们的用途,因为你稍后都会学到,但是最终你会想要获得这两个矩阵的矩阵乘积

如果你像现在这样去尝试,会获得一个错误:

np.matmul(inputs, weights)
# 显示以下错误:
# ValueError: shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)

如果你学了矩阵乘法课,那应该见过这个错误。它报告说形状不兼容,因为左边矩阵的列数 4   不等于右边矩阵的行数 3

所以这不可行,但是注意,如果你获取 weights 矩阵的转置,它会:

np.matmul(inputs, weights.T)
# 显示以下结果:
# array([[-0.01299,  0.00664,  0.13494]])

如果你获取 inputs 的转置,并调换它们的顺序也可以,就像我们在视频中展示的那样:

np.matmul(weights, inputs.T)
# 显示以下结果:
# array([[-0.01299],# 
#        [ 0.00664],
#        [ 0.13494]])

这两个答案是彼此的转置,所以你使用的乘法只取决于你想要的输出的形状。